/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package estsapp.expertos;

import estsapp.DTOs.DTONivelStock;
import estsapp.entidades.Material;
import estsapp.entidades.ModeloGestionStock;
import estsapp.entidades.Pieza;
import estsapp.entidades.Precio;
import estsapp.entidades.ProductoTerminado;
import estsapp.entidades.Proveedor;
import estsapp.estrategias.FabricaEstrategiasStock;
import estsapp.expertos.excepciones.ABMMaterialException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.hibernate.Criteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import persistencia.Conexion;
import persistencia.Fachada;
import persistencia.exceptions.ExcepcionFachada;

/**
 *
 * @author diego
 */
public class ExpertoABMMaterial implements Experto {

    public void darDeBaja(Material material) throws ABMMaterialException, ExcepcionFachada {
        //busca Productos que esten compuestos por ese material
        Criteria materialComponente = Fachada.getInstancia().crearCriterio(ProductoTerminado.class);
        materialComponente.createCriteria("detalles").add(Restrictions.eq("pieza", material));
        materialComponente.add(Restrictions.eq("vigente", true));

        List productosEncontrados = Fachada.getInstancia().buscar(ProductoTerminado.class, materialComponente);

        if (!productosEncontrados.isEmpty()) {
            throw new ABMMaterialException("Hay productos que estan compuesto por: " + material.getNombre() + ".\n"
                    + "Productos: \n" + productosEncontrados);
        }

        material.setVigente(false);
        try {
            Conexion.getInstancia().iniciarTX();
            Fachada.getInstancia().guardar(material);
            Conexion.getInstancia().confirmarTx();
        } catch (ExcepcionFachada ex) {
            Conexion.getInstancia().deshacerTx();
            throw ex;
        }

    }

    public List buscarProovedores() {
        Criteria vigente = Fachada.getInstancia().crearCriterio(Proveedor.class).add(Restrictions.eq("vigente", true));
        List proveedores = Fachada.getInstancia().buscar(Proveedor.class, vigente);
        return proveedores;
    }

    public List buscarMaterialesSegunProveedor(Proveedor proveedor) {
        Criteria preciosDeProv = Fachada.getInstancia().crearCriterio(Precio.class);

        preciosDeProv.add(Restrictions.eq("proveedor", proveedor));

        Date fechaActual = new Date();
        preciosDeProv.add(Restrictions.ge("fechaDesde", fechaActual));
        preciosDeProv.add(Restrictions.eq("fechaHasta", null));
        List precios = Fachada.getInstancia().buscar(Precio.class, preciosDeProv);


        Criteria materialPrecio = Fachada.getInstancia().crearCriterio(Material.class);

        Precio preciomat = (Precio) precios.get(0);
        materialPrecio.add(Restrictions.eq("precio", preciomat));
        System.out.println("si explota revisar el metodo este");

        return Fachada.getInstancia().buscar(Material.class, materialPrecio);
    }

    public List buscarTipoMateriales() {
        return ((ExpertoABMTipoMaterial) FabricaExpertos.getInstancia().getExperto(FabricaExpertos.expertos.ABM_TIPO_MATERIAL)).buscarTiposMateriales();
    }

    public void guardar(Material material) throws ABMMaterialException {
        validarMaterial(material);
        validarExistencia(material);
        String codigo;
        codigo = ((ExpertoCodigoBrisch) FabricaExpertos.getInstancia().getExperto(FabricaExpertos.expertos.GENERAR_CODIGO)).generarCodigo(material);
        material.setCodigo(codigo);
        material.setVigente(true);
        for (Precio precio : material.getPrecios()) {
            if (precio.getFechaDesde() == null) {
                precio.setFechaDesde(Fachada.getInstancia().getFecha());
            }
        }
        try {
            Conexion.getInstancia().iniciarTX();
            Fachada.getInstancia().guardar(material);
            Conexion.getInstancia().confirmarTx();
        } catch (ExcepcionFachada ex) {
            Conexion.getInstancia().deshacerTx();
            Logger.getLogger(ExpertoABMMaterial.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    public java.sql.Date getFechaActual() {
        return Fachada.getInstancia().getFecha();
    }

    public List buscarMateriales() {
        Criteria vigente = Fachada.getInstancia().crearCriterio(Material.class).add(Restrictions.eq("vigente", true));
        vigente.addOrder(Order.asc("codigo"));
        return Fachada.getInstancia().buscar(Material.class, vigente);
    }

    public List buscarPiezas() {
        Criteria matVigente = Fachada.getInstancia().crearCriterio(Material.class).add(Restrictions.eq("vigente", true));
        Criteria prodVigente = Fachada.getInstancia().crearCriterio(ProductoTerminado.class).add(Restrictions.eq("vigente", true));
        List piezas = Fachada.getInstancia().buscar(Material.class, matVigente);
        piezas.addAll(Fachada.getInstancia().buscar(ProductoTerminado.class, prodVigente));
        return piezas;
    }
    
    public List buscarPiezasProductoIntermedio(){
        Criteria matVigente = Fachada.getInstancia().crearCriterio(Pieza.class).add(Restrictions.eq("vigente", true));
        List piezas = Fachada.getInstancia().buscar(Material.class, matVigente);
        return piezas;
    }

    public List buscarMateriales(String nombre) {
        Criteria criterioNombre = Fachada.getInstancia().crearCriterio(Material.class);
        criterioNombre.add(Restrictions.ilike("nombre", nombre));
        return Fachada.getInstancia().buscar(Material.class, criterioNombre);
    }

    private void validarMaterial(Material material) throws ABMMaterialException {
        if (material.getNombre().length() == 0) {
            throw new ABMMaterialException("Falta ingresar Nombre");
        }
        if (material.getTipo() == null) {
            throw new ABMMaterialException("Falta seleccionar Tipo Material");
        }
        if (material.getTamaño() == null) {
            throw new ABMMaterialException("Falta tamaño");
        }
        if (material.getUnidadMedida() == null) {
            throw new ABMMaterialException("Falta ingresar Unidad de Medida");
        }
        if(material.getStock().getModelo() == null){
            throw new ABMMaterialException("Falta seleccionar Modelo de Gestión de Stock");
        }
    }

    private void validarExistencia(Material material) throws ABMMaterialException {
        if (material.getId() != null) {
            return;
        }
        Criteria nombreMaterial = Fachada.getInstancia().crearCriterio(Material.class);
        nombreMaterial.add(Restrictions.eq("nombre", material.getNombre()).ignoreCase());
        nombreMaterial.add(Restrictions.eq("vigente", true));
        if (!Fachada.getInstancia().buscar(Material.class, nombreMaterial).isEmpty()) {
            throw new ABMMaterialException("Material ya existente");
        }
    }

    public void eliminarPrecio(Precio precio) {
        try {
            Fachada.getInstancia().eliminar(precio);
        } catch (ExcepcionFachada ex) {
            System.out.println("error al eliminar Precio");
        }
    }

    public List buscarModelosStock() {
        return Fachada.getInstancia().buscar(ModeloGestionStock.class, null);
    }
    
    public List buscarNivelesStock(){
        List materiales = buscarMateriales();
        List dtos = new ArrayList();
        for (Object object : materiales) {
            Material material = (Material)object;
            DTONivelStock dto = new DTONivelStock();
            dto.setPieza(material);
            dto.setStock(material.getStock().getCantTotal());
            Float stockSeguridad = FabricaEstrategiasStock.getInstancia().getEstrategiaStock(material).calcularStockSeguridad(material);
            Float ptoPedido = FabricaEstrategiasStock.getInstancia().getEstrategiaStock(material).calcularPuntoPedido(material);
            dto.setPtoPedido(ptoPedido);
            dto.setStockSeguridad(stockSeguridad);
            dtos.add(dto);
        }
        return dtos;
    }
}
